package com.atguigu.tingshu.album.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.atguigu.tingshu.album.config.VodConstantProperties;
import com.atguigu.tingshu.album.mapper.AlbumInfoMapper;
import com.atguigu.tingshu.album.mapper.TrackInfoMapper;
import com.atguigu.tingshu.album.mapper.TrackStatMapper;
import com.atguigu.tingshu.album.service.TrackInfoService;
import com.atguigu.tingshu.album.service.VodService;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.execption.GuiguException;
import com.atguigu.tingshu.common.util.AuthContextHolder;
import com.atguigu.tingshu.common.util.UploadFileUtil;
import com.atguigu.tingshu.model.album.AlbumInfo;
import com.atguigu.tingshu.model.album.TrackInfo;
import com.atguigu.tingshu.model.album.TrackStat;
import com.atguigu.tingshu.query.album.TrackInfoQuery;
import com.atguigu.tingshu.user.client.UserClientFeign;
import com.atguigu.tingshu.vo.album.AlbumTrackListVo;
import com.atguigu.tingshu.vo.album.TrackInfoVo;
import com.atguigu.tingshu.vo.album.TrackListVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qcloud.vod.VodUploadClient;
import com.qcloud.vod.model.VodUploadRequest;
import com.qcloud.vod.model.VodUploadResponse;
import com.tencentcloudapi.vod.v20180717.models.MediaBasicInfo;
import com.tencentcloudapi.vod.v20180717.models.MediaInfo;
import com.tencentcloudapi.vod.v20180717.models.MediaMetaData;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.math.BigDecimal;
import java.util.List;
import java.util.Map;

@Slf4j
@Service
@Transactional(rollbackFor = Exception.class)
public class TrackInfoServiceImpl extends ServiceImpl<TrackInfoMapper, TrackInfo> implements TrackInfoService {

    private final TrackInfoMapper trackInfoMapper;
    private final VodConstantProperties vodConstantProperties;
    private final VodUploadClient vodUploadClient;
    private final TrackStatMapper trackStatMapper;
    private final VodService vodService;
    private final AlbumInfoMapper albumInfoMapper;
    private final UserClientFeign userClientFeign;

    @Autowired
    public TrackInfoServiceImpl(
        TrackInfoMapper trackInfoMapper,
        VodConstantProperties vodConstantProperties,
        VodUploadClient vodUploadClient,
        TrackStatMapper trackStatMapper,
        VodService vodService, AlbumInfoMapper albumInfoMapper, UserClientFeign userClientFeign) {
        this.trackInfoMapper = trackInfoMapper;
        this.vodConstantProperties = vodConstantProperties;
        this.vodUploadClient = vodUploadClient;
        this.trackStatMapper = trackStatMapper;
        this.vodService = vodService;
        this.albumInfoMapper = albumInfoMapper;
        this.userClientFeign = userClientFeign;
    }

    /**
     * 声音上传
     *
     * @param file 上传的文件
     * @return 声音地址url
     */
    @Override
    @SneakyThrows
    public JSONObject uploadTrack(MultipartFile file) {
        // 将文件存储到临时目录
        String tempPath = UploadFileUtil.uploadTempPath(vodConstantProperties.getTempPath(), file);
        // 构造声音上传Resuest请求对象
        VodUploadRequest request = new VodUploadRequest();
        request.setMediaFilePath(tempPath);
        // 调用上传
        VodUploadResponse response = vodUploadClient.upload("ap-guangzhou", request);
        // 初始化返回结果
        JSONObject result = new JSONObject();
        // 获取文件的id
        String mediaFileId = response.getFileId();
        result.put("mediaFileId", mediaFileId);
        // 获取文件的播放地址
        String mediaUrl = response.getMediaUrl();
        result.put("mediaUrl", mediaUrl);
        // 返回
        return result;
    }

    /**
     * 保存声音
     *
     * @param trackInfoVo 声音信息
     */
    @Override
    public void saveTrackInfo(TrackInfoVo trackInfoVo) {
        // 获取用户id
        Long userId = AuthContextHolder.getUserId();
        // 初始化声音
        TrackInfo trackInfo = new TrackInfo();
        // 属性迁移
        BeanUtils.copyProperties(trackInfoVo, trackInfo);
        // 找腾讯云点播获取文件的详细信息
        MediaInfo mediaInfo = vodService.getFileDetailFromTx(trackInfoVo.getMediaFileId());
        // 唯一标识
        String fileId = mediaInfo.getFileId();
        // 基础信息
        MediaBasicInfo basicInfo = mediaInfo.getBasicInfo();
        // 元信息
        MediaMetaData metaData = mediaInfo.getMetaData();
        // 媒体信息
        // 唯一标识
        trackInfo.setMediaFileId(fileId);
        // 播放地址
        trackInfo.setMediaUrl(basicInfo.getMediaUrl());
        // 时长
        trackInfo.setMediaDuration(BigDecimal.valueOf(metaData.getDuration()));
        // 类型
        trackInfo.setMediaType(basicInfo.getType());
        // 大小
        trackInfo.setMediaSize(metaData.getSize());
        // 字段补全
        // 用户id
        trackInfo.setUserId(userId);
        // 审核状态
        trackInfo.setStatus(SystemConstant.TRACK_STATUS_PASS);
        // 来源
        trackInfo.setSource(SystemConstant.TRACK_STAT_PLAY);
        // 保存
        int i = trackInfoMapper.insert(trackInfo);
        if (i <= 0) {
            throw new GuiguException(201, "添加声音失败");
        }
        // 初始化声音统计信息
        initTrackStat(trackInfo.getId());
    }

    /**
     * 分页查询声音列表
     *
     * @param pageNum        页码
     * @param pageSize       页大小
     * @param trackInfoQuery 查询条件
     * @return 声音列表
     */
    @Override
    public Page<TrackListVo> findUserTrackPage(Integer pageNum, Integer pageSize, TrackInfoQuery trackInfoQuery) {
        return trackInfoMapper.selectTrackListVoByQuery(trackInfoQuery, new Page<TrackListVo>(pageNum, pageSize));
    }

    @Override
    public void removeTrackInfo(Long trackId) {
        // 获取登录用户id
        Long userId = AuthContextHolder.getUserId();
        int i = trackInfoMapper.delete(new LambdaQueryWrapper<TrackInfo>().eq(TrackInfo::getUserId, userId).eq(TrackInfo::getId, trackId));
        if (i <= 0) {
            throw new GuiguException(201, "删除声音失败");
        }
        trackStatMapper.delete(new LambdaQueryWrapper<TrackStat>().eq(TrackStat::getTrackId, trackId));
    }

    /**
     * 更新声音信息
     *
     * @param trackInfoVo 前端提交的声音
     * @param trackId     声音id
     */
    @Override
    public void updateTrackInfo(TrackInfoVo trackInfoVo, Long trackId) {
        // 获取用户id
        Long userId = 1L;
        // 查找旧数据
        TrackInfo trackInfo = trackInfoMapper.selectOne(new LambdaQueryWrapper<TrackInfo>().eq(TrackInfo::getUserId, userId).eq(TrackInfo::getId, trackId));
        if (trackInfo == null) {
            throw new GuiguException(201, "更新声音信息失败");
        }
        // 判断是否更改了音频文件
        if (!trackInfo.getMediaFileId().equals(trackInfoVo.getMediaFileId())) {
            // 找腾讯云点播获取文件的详细信息
            MediaInfo mediaInfo = vodService.getFileDetailFromTx(trackInfoVo.getMediaFileId());
            // 唯一标识
            String fileId = mediaInfo.getFileId();
            // 基础信息
            MediaBasicInfo basicInfo = mediaInfo.getBasicInfo();
            // 元信息
            MediaMetaData metaData = mediaInfo.getMetaData();
            // 媒体信息
            // 唯一标识
            trackInfo.setMediaFileId(fileId);
            // 播放地址
            trackInfo.setMediaUrl(basicInfo.getMediaUrl());
            // 时长
            trackInfo.setMediaDuration(BigDecimal.valueOf(metaData.getDuration()));
            // 类型
            trackInfo.setMediaType(basicInfo.getType());
            // 大小
            trackInfo.setMediaSize(metaData.getSize());
        }
        // 属性转移
        BeanUtils.copyProperties(trackInfoVo, trackInfo);
        // 修改信息
        int i = trackInfoMapper.updateById(trackInfo);
        if (i <= 0) {
            throw new GuiguException(201, "修改声音失败");
        }
    }

    /**
     * 分页查询专辑的声音列表
     *
     * @param albumId
     * @param pageNum
     * @param pageSize
     * @return
     */
    @Override
    public Object findAlbumTrackPage(Long albumId, Integer pageNum, Integer pageSize) {
        // 获取当前登录用户的id，
        Long userId = AuthContextHolder.getUserId();
        Integer isVip = AuthContextHolder.getIsVip();
        Long vipExpireTime = AuthContextHolder.getVipExpireTime();
        // 本次需要查询的声音全部找出来
        Page<AlbumTrackListVo> albumTrackListVoPage = trackInfoMapper.selectAlbumTrackListVoByAlbumId(albumId, new Page<>(pageNum, pageSize));
        // 获取声音列表，未处理收费情况的
        List<AlbumTrackListVo> albumTrackListVoList = albumTrackListVoPage.getRecords();
        // 查询专辑：1.免费 2.vip免费 3.收费：a.整张专辑 b.单个声音
        AlbumInfo albumInfo = albumInfoMapper.selectById(albumId);
        // 获取专辑的收费属性：付费类型: 0101-免费、0102-vip免费、0103-付费
        String payType = albumInfo.getPayType();
        // 获取免费集数
        Integer tracksForFree = albumInfo.getTracksForFree();
        switch (payType) {
            case "0101" -> {
                // 免费 直接返回，不需要逻辑处理
                return albumTrackListVoPage;
            }
            case "0102" -> {
                // vip免费
                if (isVip == 1 && vipExpireTime > System.currentTimeMillis()) {
                    return albumTrackListVoPage;
                } else {
                    // 将免费的之外的全部换成收费
                    return makeTrackIsShowFree(albumTrackListVoList, tracksForFree, albumTrackListVoPage);
                }
            }
            case "0103" -> {
                // 付费：a.整张专辑 b.单个声音购买
                String priceType = albumInfo.getPriceType();
                if ("0201".equals(priceType)) {
                    // 单集
                    Map<String, Object> userTrackPaidMap = userClientFeign.getUserTrackPaidMap(userId, albumId);
                    // 处理声音是否收费：将购买了的换成免费的
                    albumTrackListVoPage.setRecords(albumTrackListVoList.stream().peek(
                        albumTrackListVo -> {
                            // 当前这个声音必须是没有买过并且不是免费的
                            if (albumTrackListVo.getOrderNum() > tracksForFree && userTrackPaidMap.get(albumTrackListVo.getTrackId().toString()) == null) {
                                albumTrackListVo.setIsShowPaidMark(true);
                            }
                        }).toList());
                    return albumTrackListVoPage;
                } else {
                    // 整张专辑购买：userId albumId
                    if (userClientFeign.getUserAlbumPaidStatus(userId, albumId)) {
                        // 买过
                        return albumTrackListVoPage;
                    } else {
                        // 没买过
                        return makeTrackIsShowFree(albumTrackListVoList, tracksForFree, albumTrackListVoPage);
                    }
                }
            }
            default -> {

            }
        }
        // 返回
        return null;
    }

    /**
     * 将免费集数之外的修改为收费
     *
     * @param albumTrackListVoList
     * @param tracksForFree
     * @param albumTrackListVoPage
     * @return
     */
    private Page<AlbumTrackListVo> makeTrackIsShowFree(List<AlbumTrackListVo> albumTrackListVoList, Integer tracksForFree, Page<AlbumTrackListVo> albumTrackListVoPage) {
        return albumTrackListVoPage.setRecords(albumTrackListVoList.stream().peek(
            // 判断当前是否为免费集数，不是免费则替换成收费
            albumTrackListVo -> {
                if (albumTrackListVo.getOrderNum() > tracksForFree) {
                    // 改为收费
                    albumTrackListVo.setIsShowPaidMark(true);
                }
            }
        ).toList());
    }

    /**
     * 初始化声音统计信息
     *
     * @param trackId 声音id
     */
    private void initTrackStat(Long trackId) {
        // 初始化一个统一信息对象
        TrackStat trackStat = new TrackStat();
        // 设置统计信息对象对应的声音id
        trackStat.setTrackId(trackId);
        // 设置统计的数据大小
        trackStat.setStatNum(0);

        // 播放量
        trackStat.setStatType(SystemConstant.ALBUM_STAT_PLAY);
        trackStatMapper.insert(trackStat);

        // 订阅量
        trackStat.setId(null);
        trackStat.setStatType(SystemConstant.ALBUM_STAT_SUBSCRIBE);
        trackStatMapper.insert(trackStat);

        // 购买量
        trackStat.setId(null);
        trackStat.setStatType(SystemConstant.ALBUM_STAT_BROWSE);
        trackStatMapper.insert(trackStat);

        // 评论数
        trackStat.setId(null);
        trackStat.setStatType(SystemConstant.ALBUM_STAT_COMMENT);
        trackStatMapper.insert(trackStat);
    }
}
